package org.nbict.iot.task.once.journey;

import org.nbict.iot.Pair;
import org.nbict.iot.task.once.Pointer;
import org.nbict.iot.task.once.Status;
import org.nbict.iot.task.once.TimeSpanWindow;

/**
 * 计算单次行程判断条件
 * <pre>
 *            |   end    |   start  |    login   |  logout
 *      ----------------------------------------------------
 *      end   |    e     |   s >    |      e     |    e
 *      ----------------------------------------------------
 *      start |    e <   |   s      |      s     |    e <
 *      ----------------------------------------------------
 *      note: 'e' = end status; 's' = start status;
 *            '>' = start action; '<' = stop action
 *      ====================================================
 *      case 1 'start-end':
 *            if (currentStatus == 'start'
 *                      and (comingStatus == 'end' or comingStatus ==
 *                      'logout')) {
 *                if (comingTimestamp > startTime) {
 *                  currentStatus = 'end';
 *                  endTime = comingTimestamp;
 *                  stop current travel;
 *                }
 *            } else {
 *                if (if currentTimestamp < comingTimestamp) {
 *                  currentTimestamp = comingTimestamp;
 *                }
 *            }
 *      case 2 'end-start':
 *            if (currentStatus == 'end' and comingStatus == 'start'
 *                      and comingTimestamp > currentTimestamp) {
 *                currentStatus = 'start';
 *                startTime = comingTimestamp;
 *                start new travel;
 *            } else {
 *                if (currentTimestamp < comingTimestamp) {
 *                  currentTimestamp = comingTimestamp;
 *                }
 *            }
 *
 *  problems:
 *  note: 'X' represent lost point.
 *  1. in case of 'start-end':
 *  in theory, packet e1 coming timely:
 *      s1|_________________|  e1    s2|_________________________|e2
 *
 *  in fact, e1 lost and coming later:
 *      s1|_________________|X       s2|______e1_________________|e2
 *
 *  in addition:
 *   _ _s1|_________________|X       s2|__e0__e1_________________|e2
 *  ignore e0.
 *
 *  according to algorithm above, we get:
 *      s1|_________________|X e1_ _ _ _ _ _ _s2`________________|e2
 *  lose S2->S2`
 *
 *  2. in case of 'end-start':
 *  in theory, packet s1.x coming timely:
 *      s1|___s1.x_...______|  e1___________e1.x
 *
 *  in fact, s1.x lost and coming later:
 *      s1|________...______|  e1____s1.x`__e1.x
 *  ignore s1.x`, no problem.
 *
 *  in addition:
 *  in theory, s1 coming timely:
 *      s1|__s1.x_..._______|  e1
 *  in fact, s1 lost and coming later:
 *      _ _ _s1.x_...______ |  e1____s1`____e1.x
 *  simply , we can lose s1 -> s1.x
 *
 *      _ _ _...____________|  e1__ _s1_ _e1.x_ _s1.x_ _s2
 *
 *      _ _ _...____________|  e1____s1_ _s2_ _s1.x
 *
 *  in theory
 *  s1________e1 s2__________e2
 *
 *  in fact
 *
 *  s1________e2_ _ _s2_ _ _ _
 *
 *  </pre>
 * <p>
 * 旅程状态(启动、熄火、登入、登出)
 * Created by songseven on 18/6/22.
 */
public enum JourneyStatus implements Status {

    /**
     * 当前启动状态
     */
    START {
        @Override
        public void judge(TimeSpanWindow window, Pointer coming) {
            if (coming.status() == null) return;
            //判断行程结束
            Pointer current = window.current();
            if (coming.status() == END) {
                //判断是否充电
                if (current.charged() != null) {
                    current.charged().judge(window, coming);
                }

                window.stop(coming);
                lookRemind(window, coming);
            } else {
                //判断是否充电
                if (current.charged() != null) {
                    current.charged().judge(window, coming);
                }
                //非连续启动点即超过120s
                if (coming.currentTime() - current.currentTime() > 120) { //debug
                    lookRemind(window, coming);
                }
                window.setCurrentTime(coming);
            }
        }
    },

    /**
     * 当前熄火状态
     */
    END {
        @Override
        public void judge(TimeSpanWindow window, Pointer coming) {
            if (coming.status() == null) return;

            Pointer current = window.current();
            //判断行程开始
            if (coming.status() == START) {

                //判断是否充电
                if (current.charged() != null) {
                    current.charged().judge(window, coming);
                }

                if (window.start() != null) {
                    window.stop(current);
                }
                window.start(coming);
                lookRemind(window, coming);
            } else {
                //判断是否充电
                if (current.charged() != null) {
                    current.charged().judge(window, coming);
                }
                //非连续熄火点即超过120s
                if (coming.currentTime() - current.currentTime() > 120) {
                    lookRemind(window, coming);
                }
                window.setCurrentTime(coming);
            }
        }


    },
    LOGIN,
    LOGOUT;

    @Override
    public void judge(TimeSpanWindow journey, Pointer pointer) {
        //do nothing
    }

    //查找可以压缩的点
    protected void lookRemind(TimeSpanWindow window, Pointer coming) {
        Pair<Pointer, Pointer> remind = window.getRemind();
        remind.setRight(coming);
        window.getRemindHolder().add(new Pair<>(remind.getLeft().currentTime(),
                remind.getRight().currentTime()));
        remind.clear().setLeft(coming);
    }
}
